#include <iostream>
#include "igslib_iutil.h"
#include "igslib_iserial_manager.h"
#include "igslib_igpio.h"

namespace igslib
{
    namespace gpio_sample
    {
        /*!
         * This sample demostrates writing outputs.
         * At runtime, we will set one pin high and low periodically(1 sec).
         * If it connects to a LED or a lamp, you should saw it blinks.
         *
         * Note:
         *     In M01 platform, we can use 227~230 number of pin.
         */
        static void Blink()
        {
            IGPIOManager* mgr = GetGPIOManagerInstance();
            IGPIO* gpio = mgr->NewM01GPIO(228);
            gpio->SetMode(IGPIO::mode::output);

            IGPIO::state ns = IGPIO::state::low;
            while(util::KbHit() != 27)
            {
                if (ns == IGPIO::state::low)
                {
                    ns = IGPIO::state::high;
                }
                else
                {
                    ns = IGPIO::state::low;
                }
                gpio->SetState(ns);
                util::SleepMSTime(1000);
            }
            exit(EXIT_SUCCESS);
        }
        static void ShowInput()
        {
            const int size = 12;

            ISerialManager* srm = GetSerialManagerInstance();
            //ISpi* spi = srm->NewM01Spi();	
            ISpi* spi = srm->New_ProjMCU_spi("DragonBallRace");
            spi->SetWorkingFrequency(10000000);
            bool open_result = spi->Open(ISpi::cs0);
            if (open_result == false)
            {
                throw_igslib_exception("Open SPI Node fail.");
            }

            IGPIOManager* mgr = GetGPIOManagerInstance();
            std::vector<IGPIO*> gpios;
            for ( int i = 0 ; i < size ; ++i )
            {
                IGPIO* gpio = mgr->New_ProjMCU("M01_TestPattern");
                gpio->SetMode(IGPIO::mode::input);
                gpio->SetNumber(i);
                gpio->SetSPI(spi);
                gpios.push_back(gpio);
            }
            std::string last(size,'0');
            std::cout << last << std::endl;
            while(util::KbHit() != 27)
            {
                std::string now;
                for(auto& each:gpios)
                {
                    if (each->GetState() == IGPIO::state::high)
                    {
                        now += "1";
                    }
                    else
                    {
                        now += "0";
                    }
                }
                if (last != now)
                {
                    last = now;
                    std::cout << last << std::endl;
                }
                spi->Update();
                util::SleepMSTime(16);
            }
            exit(EXIT_SUCCESS);
        }
        static void ShowOutput()
        {
            const int size = 10;

            ISerialManager* srm = GetSerialManagerInstance();
            //ISpi* spi = srm->NewM01Spi();	
            ISpi* spi = srm->New_ProjMCU_spi("DragonBallRace");
            spi->SetWorkingFrequency(10000000);
            bool open_result = spi->Open(ISpi::cs0);
            if (open_result == false)
            {
                throw_igslib_exception("Open SPI Node fail.");
            }

            IGPIOManager* mgr = GetGPIOManagerInstance();
            std::vector<IGPIO*> gpios;
            for ( int i = 0 ; i < size ; ++i )
            {
                IGPIO* gpio = mgr->New_ProjMCU("M01_TestPattern");
                gpio->SetSPI(spi);
                gpio->SetMode(IGPIO::mode::output);
                gpio->SetNumber(i);
                gpios.push_back(gpio);
            }

            auto ns = IGPIO::state::high;
            while(util::KbHit() != 27)
            {
                for(auto& each:gpios)
                {
                    each->SetState(ns);
                }
                util::Log("%s> %d\n",__func__,ns);

                if (ns == IGPIO::state::high)
                {
                    ns = IGPIO::state::low;
                }
                else
                {
                    ns = IGPIO::state::high;
                }

                spi->Update();
                util::SleepMSTime(1000);
            }
            exit(EXIT_SUCCESS);
        }
        static void WarmingTest()
        {
            const int ipc = 8;
            const int opc = 15;

            ISerialManager* srm = GetSerialManagerInstance();
            //ISpi* spi = srm->NewM01Spi();	
            ISpi* spi = srm->New_ProjMCU_spi("DragonBallRace");
            spi->SetWorkingFrequency(10000000);
            bool open_result = spi->Open(ISpi::cs0);
            if (open_result == false)
            {
                throw_igslib_exception("Open SPI Node fail.");
            }

            IGPIOManager* mgr = GetGPIOManagerInstance();
            std::vector<IGPIO*> gpios;
            for ( int i = 0 ; i < ipc ; ++i )
            {
                IGPIO* gpio = mgr->New_ProjMCU("M01_TestPattern");
                gpio->SetMode(IGPIO::mode::input);
                gpio->SetNumber(i);
                gpio->SetSPI(spi);
                gpios.push_back(gpio);
            }
            for ( int i = 0 ; i < opc ; ++i )
            {
                IGPIO* gpio = mgr->New_ProjMCU("M01_TestPattern");
                gpio->SetMode(IGPIO::mode::output);
                gpio->SetNumber(i);
                gpio->SetSPI(spi);
                gpios.push_back(gpio);
            }
            std::string last(ipc,'0');
            std::cout << last << std::endl;
            while(util::KbHit() != 27)
            {
                std::string now;
                for(auto& each:gpios)
                {
                    if (each->GetMode() == IGPIO::mode::input)
                    {
                        if (each->GetState() == IGPIO::state::high)
                        {
                            now += "1";
                        }
                        else
                        {
                            now += "0";
                        }
                    }
                    else
                    {
                        if (rand()%2)
                        {
                            each->SetState(IGPIO::state::high);
                        }
                        else
                        {
                            each->SetState(IGPIO::state::low);
                        }
                    }
                }
                if (last != now)
                {
                    last = now;
                    std::cout << last << std::endl;
                }
                spi->Update();
                util::SleepMSTime(16);
            }
            exit(EXIT_SUCCESS);
        }
    };
};
